CH376的基础入门:基于ch376与SPI总线 的stm32f103c8t6与典型常用存储设备(TF卡,U盘)的通信 您所在的位置:网站首页 u盘电路图原理解析 视频 CH376的基础入门:基于ch376与SPI总线 的stm32f103c8t6与典型常用存储设备(TF卡,U盘)的通信

CH376的基础入门:基于ch376与SPI总线 的stm32f103c8t6与典型常用存储设备(TF卡,U盘)的通信

2024-07-12 15:11| 来源: 网络整理| 查看: 265

此文章所用学习板出于通用性考虑, 使用了ch376 进行TF卡与f103c8t6的SPI总线进行通信

利用ch376强大的CMD功能 对连接的存储设备进行写入,擦除等一系列操作(此类操作以连接在ch376上的u盘为例)

此文章仅涉及ch376的基础使用方法 更多内容可以关注作者 作者会在其他文章中继续整活

硬件使用基础

在这里插入图片描述 在这里插入图片描述

引脚功能SCKclock generates the pulse signalMISOMaster input Service output(can transform the data while the MOSI is running ) duplex capable (全双工通信可行)MOSIMaster output Service inputNSSdata transform enable(检查位)

NSS 在这里插入图片描述 在这里插入图片描述

one channle can only connect to one SPI service device ,so if more than one devices are in connection ,must use more I/O pins and swap them to NSS mode and connect them to the devices contactnaturally ,every device got the very line to connect ,no need for an address to verify which the device is like I2C or CAN 一号版上的线路连接

CH376基础上 SPI与TF卡的通信 在这里插入图片描述 Header 8X2 的 2-8脚 DO,DI,CLK,CS 负责与ch376进行通信

同时由ch376 的 16-13脚引出到 S DO,S DL,SCLK,S CSS 再次引入到单片机的SPI进行通信 在这里插入图片描述

在这里插入图片描述

库文件准备

需要添加

Lib stm32f10x_spi.cBasic sys.c spi.cHardwawre ch376.c filesys.c SPI总线的初始化

spi.c

#include "spi.h" void SPI2_Init(void){ //SPI2初始化 SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);//使能SPI_2时钟 GPIO_InitStructure.GPIO_Pin = SPI2_MISO; //SPI2的MISO(PB14)为浮空输入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(SPI2PORT,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SPI2_MOSI | SPI2_SCK; //SPI2的MOSI(PB15)和SCLK(PB13)为复用推免输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(SPI2PORT,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SPI2_NSS; //SPI2的NSS(PB12)为推免输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(SPI2PORT,&GPIO_InitStructure); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//双线输入输出全双工模式,SPI双线并行允许全双工模式运行 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//设置为SPI的主机模式(SCK主动产生时钟)(SCK由MASTER产生) SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//SPI数据大小:发送8位帧数据结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//空闲状态时SCK的状态,High为高电平,Low为低电平 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//时钟相位,1表示在SCK的奇数沿边采样,2表示偶数沿边采样 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS由软件控件片选 //如果选择SPI_NSS_Hard,则需要在每次通信之前手动设置,且在之后再次手动关闭 /* //在stm32f103x_spi.h中 //#define SPI_NSS_Hard ((uint16_t)0x0000) //so we program like yhis #if !SPI_InitStructure.SPI_NSS #pragram u8 SPI2_SendByte(u8 Byte) { GPIO_Pin_12/SPI2_NSS = 0; while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI2,Byte); while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET); return SPI_I2S_ReceiveData(SPI2); SPI2_NSS = 1; } #endif */ SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//时钟的预分频值(0~256)单个时钟周期的长度,数字越大,通信越慢,信号越稳定 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //MSB高位在前 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC较验和的多项式 SPI_Init(SPI2,&SPI_InitStructure); //初始化SPI2的配置项 SPI_Cmd(SPI2,ENABLE); //使能SPI2 } //SPI2数据发+收程序(主要用于发送) u8 SPI2_SendByte(u8 Byte){ //通过SPI2口发送1个数据,同时接收1个数据 while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET); //如果发送寄存器数据没有发送完,循环等待 SPI_I2S_SendData(SPI2,Byte); //往发送寄存器写入要发送的数据 while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET); //如果接受寄存器没有收到数据,循环 return SPI_I2S_ReceiveData(SPI2); }

有关 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //MSB高位在前 在这里插入图片描述

spi.h

#ifndef __SPI_H #define __SPI_H #include "sys.h" #define SPI2PORT GPIOB //定义IO接口 #define SPI2_MOSI GPIO_Pin_15 //定义IO接口 #define SPI2_MISO GPIO_Pin_14 //定义IO接口 #define SPI2_SCK GPIO_Pin_13 //定义IO接口 #define SPI2_NSS GPIO_Pin_12 //定义IO接口 void SPI2_Init(void); u8 SPI2_SendByte(u8 Byte); #endif ch376的使用

command命令的使用与说明

ch376数据手册下载地址 阅读P3的 5、命令 对应 ch376inc.h 头文件 与 ch376.h

#ifndef __CH376_H #define __CH376_H #include "sys.h" #include "spi.h" #include "delay.h" #include "ch376inc.h" #define CH376_INTPORT GPIOA //定义IO接口 #define CH376_INT GPIO_Pin_15 //定义IO接口 void CH376_PORT_INIT( void ); /* CH376通讯接口初始化 */ void xEndCH376Cmd( void ); /* 结束SPI命令 */ void xWriteCH376Cmd( u8 mCmd ); /* 向CH376写命令 */ void xWriteCH376Data( u8 mData );/* 向CH376写数据 */ u8 xReadCH376Data( void ); /* 从CH376读数据 */ u8 Query376Interrupt( void );/* 查询CH376中断(INT#引脚为低电平) */ u8 mInitCH376Host( void ); /* 初始化CH376 */ #endif

以上两个库文件可以保证简单的使用与日后扩展

以下是与spi总线配套的驱动程序

ch376.c #include "CH376.h"

CH376接口的初始化 与 数据传输函数

/******************************************************************************* * 函 数 名 : CH376_PORT_INIT * 描 述 : 由于使用软件模拟SPI读写时序,所以进行初始化. * 如果是硬件SPI接口,那么可使用mode3(CPOL=1&CPHA=1)或 * mode0(CPOL=0&CPHA=0),CH376在时钟上升沿采样输入,下降沿输出,数 * 据位是高位在前. *******************************************************************************/ void CH376_PORT_INIT(void){ //CH376的SPI接口初始化 GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO的初始化枚举结构 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //选择端口号 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻 GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_SetBits(CH376_INTPORT,CH376_INT); //中断输入脚拉高电平 GPIO_SetBits(SPI2PORT,SPI2_NSS); //片选接口接高电平 } /******************************************************************************* SPI输出8个位数据. * 发送: u8 d:要发送的数据. *******************************************************************************/ void Spi376OutByte(u8 d){ //SPI发送一个字节数据 SPI2_SendByte(d); } /******************************************************************************* * 描 述 : SPI接收8个位数据. u8 d:接收到的数据. *******************************************************************************/ u8 Spi376InByte(void){ //SPI接收一个字节数据 while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET); //如果接受寄存器没有收到数据,循环 return SPI_I2S_ReceiveData(SPI2); } /******************************************************************************* * 描 述 : 向CH376写 数据. * 输 入 : u8 mData: * 要发送的数据. *******************************************************************************/ void xWriteCH376Data(u8 mData){ Spi376OutByte( mData ); delay_us(800); /* 确保读写周期大于0.6mS */ } /******************************************************************************* * 函 数 名 : xReadCH376Data * 描 述 : 从CH376读数据. *******************************************************************************/ u8 xReadCH376Data(void){ u8 i; delay_us(10); i = SPI2_SendByte(0xFF); return(i); }

CH376的命令函数 与 中断使用函数

/******************************************************************************* * 描 述 : 向CH376写 命令. * 输 入 : u8 mCmd:要发送的命令. *******************************************************************************/ void xWriteCH376Cmd(u8 mCmd){ GPIO_SetBits(SPI2PORT,SPI2_NSS); /* 防止之前未通过xEndCH376Cmd禁止SPI片选 */ delay_us(20); /* 对于双向I/O引脚模拟SPI接口,那么必须确保已经设置SPI_SCS,SPI_SCK,SPI_SDI为输出 * 方向,SPI_SDO为输入方向 */ GPIO_ResetBits(SPI2PORT,SPI2_NSS); /* SPI片选有效 */ Spi376OutByte( mCmd ); /* 发出命令码 */ delay_us(1700); /* 延时1.5mS确保读写周期大于1.5mS,或者用上面一行的状态查询代替 */ } /******************************************************************************* * 函 数 名 : xEndCH376Cmd 结束命令. *******************************************************************************/ void xEndCH376Cmd(void){ //结束命令 GPIO_SetBits(SPI2PORT,SPI2_NSS); //SPI片选无效,结束CH376命令 } /******************************************************************************* * 描 述 : 查询CH376中断(INT#低电平). * 返 回 : 0:无中断. 1:有中断. *******************************************************************************/ u8 Query376Interrupt(void){ u8 i; i = GPIO_ReadInputDataBit(CH376_INTPORT,CH376_INT); return( i ); }

Ch376的初始化 与 通信检查 Ps: 前面都是前摇,main.c中只使用这一条

/******************************************************************************* * 描 述 : 初始化CH376. * 返 回 : FALSE:无中断. TRUE:有中断. *******************************************************************************/ u8 mInitCH376Host(void){ u8 res; delay_ms(600); CH376_PORT_INIT( ); /* 接口硬件初始化 */ xWriteCH376Cmd( CMD11_CHECK_EXIST ); /* 测试单片机与CH376之间的通讯接口 */ xWriteCH376Data( 0x55 ); res = xReadCH376Data( ); // printf("res =%02x \n",(unsigned short)res); xEndCH376Cmd( ); if ( res != 0xAA ) return( ERR_USB_UNKNOWN ); /* 通讯接口不正常,可能原因有:接口连接异常,其它设备影响(片选不唯一),串口波特率,一直在复位,晶振不工作 */ xWriteCH376Cmd( CMD11_SET_USB_MODE ); /* 设备USB工作模式 */ xWriteCH376Data( 0x06 ); //06H=已启用的主机方式并且自动产生SOF包 ??? delay_us(20); res = xReadCH376Data( ); // printf("res =%02x \n",(unsigned short)res); xEndCH376Cmd( ); if ( res == CMD_RET_SUCCESS ){ //RES=51 命令操作成功 return( USB_INT_SUCCESS ); //USB事务或者传输操作成功 }else{ return( ERR_USB_UNKNOWN );/* 设置模式错误 */ } } 在以上程序的基础上对TF卡进行通信的程序示例

仅用于TF卡是否连接的检测 数据的读写请继续向下阅读 main.c

#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "touch_key.h" #include "relay.h" #include "oled0561.h" #include "spi.h" #include "ch376.h" #include"filesys.h" int main (void){//主程序 u8 s; delay_ms(500); //上电时等待其他器件就绪 RCC_Configuration(); //系统时钟初始化 TOUCH_KEY_Init();//触摸按键初始化 RELAY_Init();//继电器初始化 I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化 OLED_DISPLAY_8x16_BUFFER(0," YoungTalk "); //显示字符串 OLED_DISPLAY_8x16_BUFFER(2," U DISK TEST "); //显示字符串 //CH376初始化 SPI2_Init();//SPI接口初始化 if(mInitCH376Host()== USB_INT_SUCCESS){//CH376初始化 OLED_DISPLAY_8x16_BUFFER(4," CH376 OK! "); //显示字符串 } while(1){ s = CH376DiskConnect(); //读出U盘的状态 if(s == USB_INT_SUCCESS){ //检查U盘是否连接//等待U盘插入 OLED_DISPLAY_8x16_BUFFER(6," U DISK Ready! "); //显示字符串 }else{ OLED_DISPLAY_8x16_BUFFER(6," "); //显示字符串 } delay_ms(500); //刷新的间隔 } }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有